package com.googlecode.perfectable.messageable;

import java.util.List;

import com.google.common.collect.ImmutableList;

public class DispatchingMessageProcessor implements MessageProcessor<Message> {

	public static final DispatchingMessageProcessor EMPTY =
			new DispatchingMessageProcessor(ImmutableList.<ClassMessageProcessor<?>> of());
	
	private final List<ClassMessageProcessor<?>> processors;

	public static <T extends Message> DispatchingMessageProcessor single(Class<? extends T> messageClass,
			MessageProcessor<T> processor) {
		return EMPTY.also(messageClass, processor);
	}

	public <T extends Message> DispatchingMessageProcessor also(Class<? extends T> messageClass,
			MessageProcessor<T> processor) {
		List<ClassMessageProcessor<?>> newProcessors = ImmutableList.<ClassMessageProcessor<?>> builder()
				.addAll(this.processors).add(new ClassMessageProcessor<>(messageClass, processor)).build();
		return new DispatchingMessageProcessor(newProcessors);
	}

	private DispatchingMessageProcessor(List<ClassMessageProcessor<?>> processors) {
		this.processors = processors;
	}
	
	@Override
	public void process(Message message, Endpoint source) throws UnknownMessageException {
		for(ClassMessageProcessor<?> messageProcessor : this.processors) {
			messageProcessor.process(message, source);
		}
	}

	private static class ClassMessageProcessor<M extends Message> {
		
		private final Class<? extends M> dispatchedMessageClass;
		private final MessageProcessor<M> processor;
		
		public ClassMessageProcessor(Class<? extends M> dispatchedMessageClass, MessageProcessor<M> processor) {
			this.dispatchedMessageClass = dispatchedMessageClass;
			this.processor = processor;
		}
		
		public void process(Message message, Endpoint source) throws UnknownMessageException {
			Class<? extends Message> messageClass = message.getClass();
			if(this.dispatchedMessageClass.isAssignableFrom(messageClass)) {
				@SuppressWarnings("unchecked")
				M castedMessage = (M) message;
				this.processor.process(castedMessage, source);
			}
		}

	}

}
